import { Component, cls, type StyledProps } from '@knno/jsx';
import { drag } from '../../tools/drag';
import { DATA } from '../symbol';
import { splitterStyle } from './splitter.css';

interface MoveDetail {
	axis: 'x' | 'y';
	distance: number;
}

type SplitterType = 'horizontal' | 'vertical';

type SplitterProps = StyledProps<Splitter> & {
	disabled?: boolean;
	/**
	 * horizontal or vertical
	 * @default horizontal
	 */
	type?: SplitterType;
	onMoveStart?: (this: Splitter, event: PointerEvent) => void;
	onMove?: (this: Splitter, detail: MoveDetail, event: PointerEvent) => void;
	onMoveEnd?: (this: Splitter, event: PointerEvent) => void;
};

export class Splitter extends Component<SplitterProps, Splitter, HTMLDivElement> {
	private [DATA]: { overTimer?: number } = {};

	get disabled(): boolean {
		return this.el.getAttribute('disabled') != null;
	}

	setDisabled(value: boolean): this {
		if (value) {
			this.el.setAttribute('disabled', '');
		} else {
			this.el.removeAttribute('disabled');
		}
		return this;
	}

	get type(): SplitterType {
		const t = this.el.getAttribute('type') ?? 'horizontal';
		return /^horizontal|vertical$/.test(t) ? (t as SplitterType) : 'horizontal';
	}

	setType(value: SplitterType): this {
		if (!/^horizontal|vertical$/.test(value)) {
			value = 'horizontal';
		}
		this.el.setAttribute('type', value);
		return this;
	}

	protected render(): Node {
		return (
			<div
				class={cls(this.props.class, splitterStyle)}
				style={this.props.style}
				disabled={!!this.props.disabled}
				type={/^horizontal|vertical$/.test(this.props.type ?? '') ? this.props.type : 'horizontal'}
				onPointerEnter={() => {
					if (this.disabled) return;
					this[DATA].overTimer = window.setTimeout(() => {
						this[DATA].overTimer = undefined;
						this.el.classList.add('hover');
					}, 64);
				}}
				onPointerLeave={() => {
					if (typeof this[DATA].overTimer === 'number') {
						clearTimeout(this[DATA].overTimer);
						this[DATA].overTimer = undefined;
					}
					this.el.classList.remove('hover');
				}}
				onTouchStart={(e) => {
					e.preventDefault();
				}}
				onPointerDown={(e) => {
					if (this.disabled) return;
					e.preventDefault();
					const type = this.type;
					this.call('onMoveStart', e);
					drag(
						this.el,
						e,
						(evt, distance) => {
							this.call(
								'onMove',
								{
									axis: type === 'horizontal' ? 'x' : 'y',
									distance: type === 'horizontal' ? distance.x : distance.y,
								},
								evt,
							);
						},
						(e) => {
							const rect = this.el.getBoundingClientRect();
							if (
								e.clientX < rect.left ||
								e.clientX > rect.right ||
								e.clientY < rect.top ||
								e.clientY > rect.bottom
							) {
								this.el.classList.remove('hover');
							}
							this.call('onMoveEnd', new PointerEvent('moveend', e));
						},
					);
				}}
			></div>
		);
	}
}
